using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;

namespace ThreadPoolManage
{
    /* 
        调用方法
        传过来的方法必须有参，但可以传null吗，即使可能不使用
        可以不传进度数据 必须传guid
        获取实例（一般用空参，有参在有实例的时候，参数传是无作用的）：
        ThreadPoolManager.getInstance();
        或
        ThreadPoolManager.getInstance(int minThreads,int maxThreads,int increment);
        调用一个线程执行任务：
        ThreadPoolManager.getInstence().AddTaskItem(new WaitCallback(HandleFunction), object param);
        或
        ThreadPoolManager.getInstance(int minThreads,int maxThreads,int increment).AddTaskItem(new WaitCallback(HandleFunction), object param);
    */
    public class ThreadPoolManager : IDisposable
    {
        public static bool PoolEnable = false; //线程池是否可用 

        private  int maxThreads = 6; //默认最大线程数 25*核心数50  这里有给初始值 所以构造那里就不给 如果这里没有 构造就要给

        private  int minThreads = 2;  //默认最小线程数  不小于核心数16

        private  int increment = 1; //当活动线程不足的时候新增线程的默认增量

        /*
                          没有空闲线程且不能再开-等待
           初始化	 请求	
                                               （无等待队列）结束
                                  有空闲线程              
                              处理             （有等待队列）新的处理

                                                              （无等待队列，回收线程）结束                 
                                  无空闲线程但能在开线程           
                                                              （有等待队列）新的处理
          working   处理+1  新的处理+1 结束-1
          workingKeys 处理 新的处理+1 结束-1
          waitQueue等待+1 处理-1
          freeQueue 初始化+x  （有空闲线程）处理-1  （无等待队列）+1
          publicPool初始化+x [等待+1 处理-1 （有空闲线程）处理-1  （无等待队列）+1 ]
       */

        private Dictionary<string, Task> publicPool; //所有的线程(freeQueue+working)

        //public Dictionary<string, Task> PublicPool
        //{
        //    get { return publicPool; }
        //    set { publicPool = value; }
        //}
        private Queue<Task> freeQueue;  //空闲线程队列

        private Dictionary<string, Task> working;   //正在工作的线程

        private List<string> workingKeys; //正在工作的线程的唯一标识

        private Queue<Task_MainBody> waitQueue;  //等待执行工作队列

        private int max_waitQueue = 50;  //最大等待数

        private static ThreadPoolManager threadPoolManager=null;

        private int completedWorkItemCount = 0; //迄今为止已处理的工作项数。
        public int CompletedWorkItemCount { get => completedWorkItemCount; set => completedWorkItemCount = value; }

        public int pendingWorkItemCount = 0;  //当前已加入处理队列的工作项数。
        public int PendingWorkItemCount { get => pendingWorkItemCount; set => pendingWorkItemCount = value; }

        private int threadCount;  //当前存在的线程池线程数。
        public int ThreadCount { get => threadCount; set => threadCount = value; }

        public  Dictionary<string, Dictionary<string, string>> taskProgress = new Dictionary<string, Dictionary<string, string>>();//用于存储当前进度 格式 当前完成数/任务总数

        /// <summary>
        /// 返回当前有效可用线程数 负数的情况是还有负数绝对值个任务在等待
        /// </summary>
        /// <returns></returns>
        public int GetAvailableThreads()
        {
            return maxThreads - working.Count- waitQueue.Count;
        }

        //static Dictionary<string, int> JobQuotaRegisterBook; //线程使用登记本

        ////线程使用登记 +&-
        //private static void JobQuotaRegister(string userid, int num)
        //{
        //    //判断是否在
        //    if (JobQuotaRegisterBook.ContainsKey(userid))
        //    {
        //        JobQuotaRegisterBook[userid] += num;
        //    }
        //    else
        //    {
        //        //进行登记
        //        JobQuotaRegisterBook.Add(userid, num);
        //    }
        //}
        ////从数据库获取用户的最大可提交任务数 ，也可能定义一个固定值但只能每个人都一样
        //private static int GetJobQuotaLimit(string userid)
        //{
        //    return 4;
        //}
        //设置最大线程数

        //设置最大线程数
        public void Setmaxthread(int Value)
        {
            lock (this)
            {
                maxThreads = Value;
            }
        }

        /// <summary>
        /// 设置最小线程数
        /// </summary>
        /// <param name="Value"></param>
        public void Setminthread(int Value)
        {
            lock (this)
            {
                minThreads = Value;
            }
        }

        /// <summary>
        /// 获取最大线程数
        /// </summary>
        public int GetMaxThreads()
        {
            return maxThreads;
        }

        /// <summary>
        /// 获取最小线程数
        /// </summary>
        public int GetMinThreads()
        {
            return minThreads;
        }

        /// <summary>
        /// 获取增量
        /// </summary>
        /// <param name="workerThreads"></param>
        /// <param name="completionPortThreads"></param>
        public int GetIncrement()
        {
            return increment;
        }

        /// <summary>
        /// 设置增量
        /// </summary>
        /// <param name="Value"></param>
        public void Setincrement(int Value)
        {
            lock (this)
            {
                increment = Value;
            }
        }

        /// <summary>
        /// 设置最大线等待任务数
        /// </summary>
        /// <param name="Value"></param>
        public void Setmax_WaitJob(int Value)
        {
            lock (this)
            {
                max_waitQueue = Value;
            }
        }

        /// <summary>
        /// 获取线程池状态
        /// </summary>
        /// <returns></returns>
        public Dictionary<string,int> GetPoolState()
        {
            Dictionary<string, int> poolState  = new Dictionary<string, int>();
            //线程池是否可用 
            poolState.Add("PoolEnable",Convert.ToInt32(PoolEnable));
            //默认最大线程数
            poolState.Add("maxThreads", maxThreads);
            //默认最小线程数
            poolState.Add("minThreads", minThreads);
            //当活动线程不足的时候新增线程的默认增量
            poolState.Add("increment", increment);
            //所有的线程
            poolState.Add("publicPool", publicPool.Count);
            //空闲线程队列
            poolState.Add("freeQueue", freeQueue.Count);
            //正在工作的线程
            poolState.Add("working", working.Count);
            //等待执行工作队列
            poolState.Add("waitQueue", waitQueue.Count);
            //最大等待数
            poolState.Add("max_waitQueue", max_waitQueue);
            //迄今为止已处理的工作项数。
            poolState.Add("completedWorkItemCount", completedWorkItemCount);
            //当前已加入处理队列的工作项数。
            poolState.Add("pendingWorkItemCount", pendingWorkItemCount);
            //当前存在的线程池线程数。
            threadCount = working.Count + freeQueue.Count;
            poolState.Add("threadCount", threadCount);
            return poolState;
    }

        #region 构造函数
        private ThreadPoolManager(int minThreads, int maxThreads, int increment)
        {
            this.minThreads = minThreads;
            this.maxThreads = maxThreads;
            this.increment = increment;
            PoolEnable = true;
            initThreadTool();
        }

        private ThreadPoolManager()
        {
            PoolEnable = true;
            initThreadTool();
        }
        #endregion
        private static object Singleton_Lock = new object(); //锁同步 不加锁可能会同时调用多判空 导致单例失效
        /// <summary>
        /// 获取实例 利用静态实现单例
        /// </summary>
        /// <param name="minThreads">初始化最小线程数</param>
        /// <param name="maxThreads">初始化最大线程数</param>
        /// <param name="increment">线程增量数</param>
        /// <returns></returns>
        public static ThreadPoolManager getInstance(int minThreads, int maxThreads, int increment)
        {
            lock (Singleton_Lock)
            {
                if (threadPoolManager==null)
                {
                    threadPoolManager = new ThreadPoolManager(minThreads, maxThreads, increment);
                }
            }
            return threadPoolManager;
        }
        public static ThreadPoolManager getInstance()
        {
            lock(Singleton_Lock)
            {
                if (threadPoolManager == null)
                {
                    threadPoolManager = new ThreadPoolManager();
                }
            }
            return threadPoolManager;
        }


        /// <summary>
        /// 初始化线程池
        /// </summary>
        void initThreadTool() {

            publicPool = new Dictionary<string, Task>();

            working = new Dictionary<string, Task>();

            workingKeys = new List<string>();

            freeQueue = new Queue<Task>();

            waitQueue = new Queue<Task_MainBody>();

            Task t = null;
           
            //先创建最小线程数的线程

            for (int i = 0; i < minThreads; i++)
            {
                t = new Task();
                //注册线程完成时触发的事件
                t.WorkComplete += new Action<Task>(t_WorkComplete);
                //加入到所有线程的字典中
                publicPool.Add(Guid.NewGuid().ToString(), t);
                //因为还没加入具体的工作委托就先放入空闲队列
                freeQueue.Enqueue(t);
            }

        }

        /// <summary>
        /// 线程执行完毕后的触发事件
        /// </summary>
        /// <param name="obj"></param>
        void t_WorkComplete(Task obj)
        {
            //同一时间只能有一个人操作成功不然可能造成脏读、不可重复读和幻读啥的
            lock (this)
            {
                //任务计数
                completedWorkItemCount += 1;
                //首先因为工作执行完了，所以从正在工作字典里删除
                working.Remove(obj.Key);
                workingKeys.Remove(obj.Key);
                //检查是否有等待执行的操作，如果有等待的优先执行等待的任务
                if (waitQueue.Count > 0)
                {
                    //先要注销当前的线程，将其从线程字典删
                    publicPool.Remove(obj.Key);
                    obj.Close();
                    //从等待任务队列提取一个任务
                    Task_MainBody item = waitQueue.Dequeue();
                    Task nt = null;
                    //如果有空闲的线程，就是用空闲的线程来处理
                    if (freeQueue.Count > 0)
                    {
                        nt = freeQueue.Dequeue();
                    } 
                    if (freeQueue.Count ==0&&publicPool.Values.Count < maxThreads)
                    {
                        //如果没有空闲的线程就再新创建一个线程来执行
                        nt = new Task();
                        nt.id = item.id;
                        nt.Key = item.id;
                        publicPool.Add(nt.Key, nt);
                        nt.WorkComplete += new Action<Task>(t_WorkComplete);
                    }
                    else if((freeQueue.Count == 0 && publicPool.Values.Count == maxThreads))
                    {
                        return;
                    }
                    //设置线程的执行委托对象和上下文对象
                    nt.taskWorkItem = item.waitCallback;
                    nt.contextdata = item.Context;
                    nt.id = item.id;
                    nt.Key = item.id;
                    //添加到工作字典中
                    working.Add(nt.id, nt);
                    workingKeys.Add(nt.id);
                    //唤醒线程开始执行
                    nt.Active();
                    //任务计数 新任务+1
                    pendingWorkItemCount += 1;
                }
                else
                {

                //如果没有等待执行的操作就回收多余的工作线程
                if (freeQueue.Count > minThreads)
                {
                    //当空闲线程超过最小线程数就回收多余的这一个
                    publicPool.Remove(obj.Key);
                    obj.Dispose();
                }else{
                    //如果没超过就把线程从工作字典放入空闲队列
                    obj.contextdata = null;
                    freeQueue.Enqueue(obj);
                }
                }
                //任务计数 结束任务-1
                pendingWorkItemCount -= 1;
                //清除进度已完成的任务进度
                taskProgress.Remove(obj.id);
            }
        }

        /// <summary>
        /// 添加工作委托
        /// </summary>
        /// <param name="TaskItem">WaitCallback必须带参</param>
        /// <param name="Context"></param>
        /// <returns>成功：工作线程ID 等待中：-1 失败：-2</returns>
        public string AddTaskItem(WaitCallback TaskItem, object Context,string id)
        {
            //同一时间只能有一个人操作成功不然可能造成脏读、不可重复读和幻读啥的
            lock (this)
            {
                if (!IsGUID(id))
                {
                    return "id不是GUID";
                }
                //判断id是否重复
                var havaWorking = working.FirstOrDefault(x => x.Key.Equals(id)).Value;
                var havaWaitQueue = waitQueue.FirstOrDefault(x => x.id.Equals(id));
                if (havaWorking != null|| havaWaitQueue!=null)
                {
                    return "id已使用";
                }
                //线程池要保证在RUNNING的状态下执行任务。
                if (PoolEnable) {
                    Task t = null;
                    int len = publicPool.Values.Count;
                    //如果空闲列表为空并且线程没有到达最大值则继续开线程
                    if (freeQueue.Count == 0 && len < maxThreads)
                    {
                        //如果没有空闲队列了，就根据增量创建线程
                        for (int i = 0; i < increment; i++)
                        {
                            //判断线程的总量不能超过maxThreads
                            if ((len + i + 1) <= maxThreads)
                            {
                                t = new Task();
                                //设置执行委托
                                t.SetWorkItem(TaskItem, Context, id);
                                //设置完成响应事件
                                t.WorkComplete += new Action<Task>(t_WorkComplete);
                                //加入线程字典
                                publicPool.Add(t.Key, t);
                                //加入空闲队列
                                freeQueue.Enqueue(t);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    //如果空闲列表为空并且线程到达最大值则加入等待队列
                    else if (freeQueue.Count == 0 && len == maxThreads)
                    {
                        if (max_waitQueue >= waitQueue.Count)
                        {
                            //如果线程达到maxThreads就把任务加入等待队列
                            waitQueue.Enqueue(new Task_MainBody() { Context = Context, waitCallback = TaskItem,id =id});
                            return "已加入等待队列";
                        }
                        else
                        {
                            return "等待队列已满";
                        }
                    }

                    #region 空闲队列有的用
                    //从空闲队列pop一个线程
                    t = freeQueue.Dequeue();
                    //设置执行委托
                    t.SetWorkItem(TaskItem, Context, id);
                    //加入工作字典
                    working.Add(t.id, t);
                    workingKeys.Add(t.id);
                    //设置状态对象
                    //t.contextdata = Context;
                    Console.WriteLine(Context + TaskItem.Method.Name);

                    //唤醒线程开始执行
                    t.Active();
                    //任务计数 新任务+1
                    pendingWorkItemCount += 1;
                    return t.Key;
                    #endregion
                }
                else
                {
                    return "线程池不可用";
                } 
            }
        }

        /// <summary>
        /// 通知在当前任务完成后关闭线程
        /// </summary>
        /// <param name="threadId"></param>
        public void CloseAfterCurrTask(string threadId)
        {
            //获取线程NTask对象
            Task task = getTask(threadId);
            if(task!=null){
                task.Close();
            }
           
        }

        /// <summary>
        /// 根据线程ID停止一个线程
        /// </summary>
        /// <param name="threadId"></param>
        /// 
        //public void CloseThread(string threadId) {

        //    //获取线程NTask对象
        //    Task task = getTask(threadId);

        //    if (task != null)
        //    {
        //        //从工作列表删除，并添加至空闲
        //        try
        //        {
        //            working.Remove(task.Key);
        //            workingKeys.Remove(task.Key);
        //            freeQueue.Enqueue(task);
        //        }
        //        catch
        //        {
        //        }
        //        //task.m_Thread.Suspend();  这里执行完走不下去了
        //        task.locks.WaitOne();  
        //    }
        //}

        /// <summary>
        /// 对线程的基本操作  线程池里开始、终止都应随流程推进自动不能随意控制
        /// </summary>
        /// <param name="threadId"></param>
        /// <param name="operation"></param>
        //public void threadBaseOperation(string threadId, string operation, int seconds)
        //{
        //    //获取线程NTask对象
        //    Task task = getTask(threadId);
        //    try {
        //        switch (operation)
        //        {
        //            //开始线程
        //            case "Start":
        //                try
        //                {
        //                    task.thread.Start(); break;
        //                }
        //                catch
        //                {
        //                    break;
        //                } 
        //            //从线程内部引发异常终止线程线程
        //            case "Abort":
        //                task.thread.Abort(); break;
        //            //组织调用线程直到终止
        //            case "Join":
        //                task.thread.Join(); break;
        //                ////挂起线程
        //                //case "Suspend":
        //                //    task.thread.Suspend(); break;
        //                ////继续挂起的线程
        //                //case "Resume":
        //                //    task.thread.Resume(); break;
        //                //Thread.Sleep()写在哪个线程就挂起哪个线程 一下对象不适用
        //                //挂起
        //                //case "Sleep":
        //                //    Thread.Sleep(seconds); break;
        //                //case "ResetAbort":
        //                //    Thread.ResetAbort(); break;
        //                ////线程等待
        //                //case "SpinWait":
        //                //    Thread.SpinWait(seconds); break;
        //                ////使当前线程由执行状态，变成为就绪状态，让出cpu时间，在下一个线程执行时候，此线程有可能被执行，也有可能没有被执行。
        //                //case "Yield":
        //                //    Thread.Yield(); break;
        //        }
        //    }
        //    catch(Exception e) {
        //        AddLogEntity("threadBaseOperation错误：" + e.Message.ToString()) ;
        //    }
          
        //}

        /// <summary>
        /// 根据线程ID获取一个线程实例 在等待不适用（没有实例化没有id,ManagedThreadId只读）
        /// </summary>
        /// <param name="threadId"></param>
        /// <returns></returns>
        public Task getTask(string threadId)
        {
            //List<NTask> list = working.Select(x => x.Value).Where(x => x.thread.ManagedThreadId == threadId).ToList();
            //if(list.Count>0){
            //    return list[0];
            //}
            for (int i = 0; i < workingKeys.Count; i++)
            {
                string key = workingKeys[i];
                Task n = working.ContainsKey(key)?working[key]:null;
                if(n!=null&&n.Key==threadId){
                    return n;
                }
            }
            return null;
        }


        /// <summary>
        /// 查询任务进度（任务中达到任务的多少个单位就自己用threadId和当前进度写到变量tskProgress）
        /// </summary>
        /// <param name="threadId"></param>
        /// <returns></returns>
        public string GetTaskProgress(string id)
        {
            //获取进度
            //var Progress = taskProgress.FirstOrDefault(x => x.Key .Equals(id)).Value; 这种写法会导致：集合已经被修改,不能使用枚举。
            Dictionary<string, string> Progress =new Dictionary<string, string>();
            String[] keyArr = taskProgress.Keys.ToArray<String>();
            for (int i = 0; i < keyArr.Length; i++)
            {
                if (keyArr[i].Equals(id))
                {
                    Progress = taskProgress[keyArr[i]];
                }   
            }
            if (Progress!=null&& Progress.Count>0)
               {
                        return Progress.FirstOrDefault().Key+"/"+ Progress.FirstOrDefault().Value;
               }
               else
               {
                        return "没有获取到当前进度";
               }
        }
        /// <summary>
        /// 查询任务进度（任务中达到任务的多少个单位就自己用threadId和当前进度写到session）
        /// </summary>
        /// <param name="threadId"></param>
        /// <returns></returns>
        public Dictionary<string,Dictionary<string,string>> GetAllTaskProgress()
        {
            if (taskProgress != null)
            {
                return taskProgress;
            }
            else
            {
                return new Dictionary<string, Dictionary<string, string>>();
            }
        }
        /// <summary>
        /// 添加进度数据
        /// </summary>
        /// <param name="threadId"></param>
        /// <param name="current"></param>
        /// <param name="allCount"></param>
        public void AddTaskProgress(string threadId, int current, int allCount)
        {
            //判断字典里已经有了么
            var Progress = taskProgress.FirstOrDefault(x => x.Key.Equals(threadId)).Value;
            if (Progress==null)
            {
                Dictionary<string, string> progress = new Dictionary<string, string>();
                progress.Add(current.ToString(), allCount.ToString());
                taskProgress.Add(threadId, progress);
            }
            else
            {
                Dictionary<string, string> progress = new Dictionary<string, string>();
                progress.Add(current.ToString(), allCount.ToString());
                Progress[threadId] = allCount.ToString();
            }
          
        }
        /// <summary>
        /// 获取线程任务
        /// </summary>
        /// <param name="threadId"></param>
        /// <returns></returns>
        public WaitCallback getTask_MainBody(string threadId)
        {
            for (int i = 0; i < workingKeys.Count; i++)
            {
                string key = workingKeys[i];
                Task n = working.ContainsKey(key) ? working[key] : null;
                if (n != null && n.Key== threadId)
                {
                    return n.taskWorkItem;
                }
            }
            return null;
        }

        //回收资源实现IDisposable->Dispose方法
        public void Dispose()
        {
            PoolEnable = false;
            //throw new NotImplementedException();
            foreach (Task t in publicPool.Values)
            {
                //关闭所有的线程
                using (t) { t.Close(); }
            }

            publicPool.Clear();

            working.Clear();

            workingKeys.Clear();

            waitQueue.Clear();

            freeQueue.Clear();

        }

        /// <summary>
        /// 新增异常日志 新增日志用到力软框架 没有环境 得自己定义
        /// </summary>
        /// <param name="jsonMessage">消息内容</param>
        /// <param name="userId">操作者Id</param>
     /*   public void AddLogEntity(string jsonMessage)
        {
            LogEntity logEntity = new LogEntity();
            logEntity.F_CategoryId = 4;//1-登陆2-访问3-操作4-异常
            logEntity.F_OperateTypeId = ((int)OperationType.Exception).ToString();//参照枚举OperationType
            logEntity.F_OperateType = EnumAttribute.GetDescription(OperationType.Exception);//参照枚举OperationType
            logEntity.F_OperateAccount = "ThredPoolManage"; //操作人名称
            logEntity.F_OperateUserId = "ThredPoolManage"; //操作人ID
            logEntity.F_ExecuteResult = -1;//执行结果状态，-1：其他；0：失败；1：成功；
            logEntity.F_ExecuteResultJson = jsonMessage;//消息内容json格式
            logEntity.WriteLog();
        }*/
        /// <summary>
        /// 判断字符串是不是GUID
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public bool IsGUID(string expression)
        {
            if (expression != null)
            {
                Regex guidRegEx = new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
                return guidRegEx.IsMatch(expression);
            }
            return false;
        }
        /// <summary>
        /// 线程池开关
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public void PoolSwitch()
        {
            PoolEnable = !PoolEnable;
        }
        
    }
}